﻿/*
 *  Sqlite ORM - PUBLIC DOMAIN LICENSE
 *  Copyright (C)  2010-2012. Ian Quigley
 *  
 *  This source code is provided 'As is'. You bear the risk of using it.
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using SqliteORM;
using SqliteORM.ExpressionTree;
using SqliteORM.Tests.Model;
using SubSpec;
using Xunit;

namespace SqliteORM.Tests
{
	public class WhereExpression
	{
        [Specification]
        public void Simple()
        {
            Expression<Func<TableIdString, object>> expression = null;
            Where clause = null;

            "Given a simple (t => t.Id == 2) expression".Context(() =>
            {
                DbConnection.Initialise("Data Source=test.db3");
                expression = t => t.Id == 2;
            });

            "When converting that to a Where clause".Do(() =>
                    clause = (new WhereExpressionVisitor<TableIdString>()).ConvertToWhere(expression));

            "Expect Where.Eq('Id', 2)".Observation(() =>
                                                    Assert.Equal(Where.Equal("Id", 2), clause));

        }

        [Specification]
        public void SimpleEnum()
        {
            Expression<Func<TableEnum, object>> expression = null;
            Where clause = null;

            "Given a simple (t => t.Enum == MyEnum.CheckThree) expression".Context(() =>
            {
                DbConnection.Initialise("Data Source=test.db3");
                expression = t => t.Enum == MyEnum.CheckThree;
            });

            "When converting that to a Where clause".Do(() =>
                    clause = (new WhereExpressionVisitor<TableEnum>()).ConvertToWhere(expression));

            "Expect Where.Eq('Enum', \"CheckThree\")".Observation(() =>
                                                    Assert.Equal(Where.Equal("Enum", "CheckThree"), clause));

        }

        [Specification]
        public void MultipleExpressions()
        {
            Expression<Func<TableTypes, object>> expression = null;
            Where clause = null;
            var now = DateTime.Now;

			"Given an expression (t => t.Decimal < 23.33M && t.Date > now)".Context(() =>
            {
                DbConnection.Initialise("Data Source=test.db3");
                expression = t => t.Decimal < 23.33M ;
            });

            "When converting that to a Where clause".Do(() =>
                    clause = (new WhereExpressionVisitor<TableTypes>()).ConvertToWhere(expression));

            "Expect matching Where clause".Observation(() => 
                Assert.Equal( Where.LessThan("Decimal", 23.33M), clause));

        }

		public class SomeClass
		{
			public int X = 99;
			public int Y { get { return 79; } }
		}

		[Specification]
		public void ValueFromClass()
		{
			SomeClass something = new SomeClass();	

			Expression<Func<TableTypes, object>> expression = null;
			Where clause = null;

			"Given an expression (t => t.Long == something.X && t.Id == something.Y)".Context(() =>
			{
				DbConnection.Initialise("Data Source=test.db3");
				expression = t => t.Long == something.X && t.Id == something.Y;
			});

			"When converting that to a Where clause".Do(() =>
					clause = (new WhereExpressionVisitor<TableTypes>()).ConvertToWhere(expression));

			"Expect matching Where clause with literal values for X & Y".Observation(() =>
													Assert.Equal( Where.And( Where.Equal( "Long", 99), Where.Equal("PK_ID",79)), clause));

		}

        [Specification]
        public void MultipleExpressionTypes()
        {
            DateTime now = DateTime.Now;
            ValuesClass values = new ValuesClass();

            List<Expression<Func<TableTypes, bool>>> expressionList = new List<Expression<Func<TableTypes, bool>>>()
                {
                   /* tc => tc.Id == 99,
                    tc => tc.Id == values.Value1,
                    tc => tc.Id == ValuesClass.Value2,
                    tc => tc.Id == values.Value3,
                    tc => tc.Id == ValuesClass.Value4,
                    tc => tc.Id == values.Value5,
                    tc => tc.Id == values.Value6.Invoke(),
                    tc => tc.Id == values.Value7(),
                    tc => tc.Id == values[8],
                    tc => tc.Id == values.Value9.Invoke(9),
                    tc => tc.Id == values.Get10(),
                    tc => tc.Id == ValuesClass.Get11(),                    
                    tc => tc.Id == ValuesClass.GetValStatic(9),
                    tc => tc.Id == values.GetVal(9), */
                    tc => tc.Id == values.GetValCapture(9, now)
               //     tc => tc.Id == ValuesClass.GetValCaptureStatic(9, now)
                };

            foreach (var expr in expressionList)
                MultipleExpressionTypes_Test(expr);
        }

		public void MultipleExpressionTypes_Test(Expression<Func<TableTypes,bool>> expression)
		{
			Where clause = null;

            string.Format("Given an expression ({0})",expression).Context(() =>
			{
				DbConnection.Initialise("Data Source=test.db3");				
			});

			"When converting to a Where clause".Do(() =>
					clause = (new WhereExpressionVisitor<TableTypes>()).ConvertToWhere(expression));

			"Expect matching Where clause with literal value for Id"
                .Observation(() => Assert.Equal(  Where.Equal("PK_ID", 99) , clause));

		}

        public class ValuesClass
        {
            public int Value1 = 99;
            public static int Value2 = 99;
            public readonly int Value3 = 99;
            public const int Value4 = 99;
            public int Value5 { get { return 99; } }
            public Func<int> Value6 = () => { return 99; };
            public int Value7() { return 99; }
            public int this[int i] { get { return 90 + i; } }
            public Func<int, int> Value9 = i => i + 90;

            public int Get10()
            {
                return 99;
            }

            public static int Get11()
            {
                return 99;
            }

            public int GetVal(int val)
            {
                return 90 + val;
            }

            public static int GetValStatic(int val)
            {
                return 90 + val;
            }

            public int GetValCapture(int val, DateTime when)
            {
                return 90 + val;
            }

            public static int GetValCaptureStatic(int val, DateTime when)
            {
                return 90 + val;
            }
        }
    }
}
